require 'net/http' # builtin
require 'json' # builtin
require 'rongcloudv1/signature' # my lib
require 'logger' # builtin

module RongCloud
  module Request
    include Signature

    def request(path, params = nil, content_type = :form_data)
      uri = get_uri(path)
      req = init_request(uri, params, content_type)

      use_ssl = uri.scheme = "https"
      timeout = RongCloud::Config.timeout
      request_options = {use_ssl: use_ssl, open_timeout: timeout, read_timeout: timeout}

      res = Net::HTTP.start(uri.hostname, uri.port, request_options) do |http|
        inspect_debug_informations(req, uri, request_options)
        http.request(req)
      end

      inspect_debug_informations(res)
      handle_response(res)
    end


    private
    def get_uri(path)
      url = "#{RongCloud::Config.host}/#{path.gsub(/^\//, "")}"
      URI(url.end_with?(".json") ? url : "#{url}.json") 
    end

    def init_request(uri, params, content_type)
      req = Net::HTTP::Post.new(uri)
      signed_headers.each {
        |header, value| req[header] = value
      }

      case content_type
      when :form_data
        req.set_form_data(params) if params.respond_to?(:map)
      when :json
        req.body = params.to_json
        req["Content-Type"] = "application/json"
      end
    end

    def handle_response(res)
      json = JSON.parse(res.body)
      case res
      when Net::HTTPOK
        json
      else
        error = (HTTP_CODE_TO_ERRORS_MAP[res.code] || RequestError).new(json["errorMessage"])
        error.business_code = json["code"]
        raise error # throw error
    end


    def inspect_debug_informations(*objects)
      return unless RongCloud::Config.debug_mode
      
      objects.each do |obj|
        begin
          case 
          when obj.is_a?(URI::Generic)
            logger.debug("Requesting #{obj.hostname}:#{obj.port}")
          when obj.is_a?(Net::HTTPGenericRequest)
            logger.debug("request method: #{obj.method}, headers: #{obj.to_hash}, raw body: #{obj.body}")
          when obj.is_a?(Net::HTTPResponse)
            logger.debug("response headers: #{obj.to_hash}, raw body: #{obj.body}")
          else
            logger.debug(obj.inspect)
          end
        rescue
        end

    end

    def logger
      @logger ||= ::Logger.new("log/rong_cloud_debug.log")
    end


  end # Request

end

